package com.yy.service;

import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @Author: chen
 * @Date: 2022/9/23 10:15
 * @Desc: redisson
 */
@Service
public class RedissonStockService {
    @Autowired
    RedissonClient redissonClient;
    @Autowired
    StringRedisTemplate redisTemplate;

    public void deduct() {
        RLock lock = redissonClient.getLock("lock");
        lock.lock();

        try {
            String stock = redisTemplate.opsForValue().get("stock");
            if (null != stock && stock.length() > 0) {
                int count = Integer.parseInt(stock);
                if (count > 0) {
                    redisTemplate.opsForValue().set("stock", String.valueOf(--count));
                }
            }
        } finally {
            lock.unlock();
        }
    }

    /**
     * 测试redisson公平锁
     *
     * @param id
     */
    public void fairLock(long id) {
        RLock fairLock = redissonClient.getFairLock("fairLock");

        fairLock.lock();
        try {
            TimeUnit.SECONDS.sleep(10);
            System.out.printf("测试公平锁, id=%s-------->\n", id);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            fairLock.unlock();
        }
    }

    /**
     * 测试读锁
     */
    public void readLock() {
        RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock");
        rwLock.readLock().lock(10, TimeUnit.SECONDS);
        System.out.println("执行读取操作-------->");
        // rwLock.readLock().unlock();
    }

    /**
     * 测试写锁
     */
    public void writeLock() {
        RReadWriteLock rwLock = redissonClient.getReadWriteLock("rwLock");
        rwLock.writeLock().lock(10, TimeUnit.SECONDS);
        System.out.println("执行写入操作-------->");
        // rwLock.writeLock().unlock();
    }

    /**
     * 测试semaphore
     * 资源量的设置需要注意,如果redis里面有,不会被删除,重启程序会直接使用
     * 导致修改资源不生效,需要先删除key,再修改资源
     */
    public void semaphoreLock() {
        RSemaphore semaphore = redissonClient.getSemaphore("semaphore");
        semaphore.trySetPermits(3);
        try {
            semaphore.acquire();
            redisTemplate.opsForList().rightPush(
                    "semaphoreLog",
                    Thread.currentThread().getName() + ": 获取到了任务资源,开始执行业务逻辑"
            );

            TimeUnit.SECONDS.sleep(new Random().nextInt(10) + 10);

            redisTemplate.opsForList().rightPush(
                    "semaphoreLog",
                    Thread.currentThread().getName() + ": 处理完了业务逻辑,开始释放资源"
            );
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }

    }

    /**
     * latch测试
     */
    public void latchLock() {
        RCountDownLatch latchLock = redissonClient.getCountDownLatch("latchLock");
        latchLock.trySetCount(3);

        try {
            latchLock.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * count down测试
     */
    public void countDownLock() {
        RCountDownLatch latchLock = redissonClient.getCountDownLatch("latchLock");
        latchLock.countDown();
    }
}
